package com.zzyl.nursing.service.impl;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 设备Service业务层处理
 * 
 * @author xuanzhi
 * @date 2025-09-22
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private IoTDAClient client;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询设备
     * 
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id)
    {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备列表
     * 
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device)
    {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int updateDevice(Device device)
    {
        return deviceMapper.updateById(device);
    }

    /**
     * 批量删除设备
     * 
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids)
    {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除设备信息
     * 
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id)
    {
        return deviceMapper.deleteById(id);
    }

    @Override
    public void syncProductList() {
        //1.从华为云获取产品数据
        ListProductsRequest request = new ListProductsRequest();//创建请求参数对象
        request.setLimit(50);//设置参数
        ListProductsResponse response = client.listProducts(request);//发送请求
        List<ProductSummary> products = response.getProducts();
        //2.将产品数据存储到redis中
        redisTemplate.opsForValue().set(Constants.PRODUCTS_KEY, JSONUtil.toJsonStr(products));
    }

    @Override
    public List<ProductVo> allProduct() {
        String s = (String) redisTemplate.opsForValue().get(Constants.PRODUCTS_KEY);//从redis中获取value
        if(StrUtil.isBlank(s)){
            return null;
        }
        List<ProductVo> list = JSONUtil.toList(s, ProductVo.class);
        return  list;
    }

    /**
     * 添加注册设备
     * @param dto
     */
    @Override
    public void registerDevice(DeviceDto dto) {
        //1.查看设备名称是否重复
        Long count = lambdaQuery().eq(Device::getDeviceName, dto.getDeviceName()).count();
        if(count!=null&&count>0){
            throw new RuntimeException("设备名称重复");
        }
        //2.查看设备标识是否重复
        Long count1 = lambdaQuery().eq(Device::getNodeId, dto.getNodeId()).count();
        if(count1!=null&&count1>0){
            throw new RuntimeException("设备标识重复");
        }
        //3.查看同一位置是否绑定了相同的产品
        Long count2 = lambdaQuery()
                .eq(Device::getBindingLocation, dto.getBindingLocation())
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(Device::getPhysicalLocationType, dto.getPhysicalLocationType())
                .eq(Device::getProductKey, dto.getProductKey())
                .count();
        if(count2!=null&&count2>0){
            throw new RuntimeException("设备标识重复");
        }
        //4.注册设备
        //先将设备信息保存到华为云
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();
        body.setNodeId(dto.getNodeId());//设备标识,如:watch01,必传
        body.setDeviceName(dto.getDeviceName());//设备名字,如:手表1号,可传
        body.setProductId(dto.getProductKey());//产品id,必传
        AuthInfo authInfo=new AuthInfo();
        String s = IdUtil.fastSimpleUUID();//随机生成sercet密钥,可传
        authInfo.setSecret(s);
        body.setAuthInfo(authInfo);
        request.setBody(body);
        //要对调用的第三方接口进行校验
        AddDeviceResponse response = null;
        try {
            response = client.addDevice(request);
            if(response==null){
                throw new RuntimeException("调用华为云返回值为null");
            }
        } catch (Exception e) {
            throw new RuntimeException("调用华为云接口失败");
        }
        String deviceId = response.getDeviceId();//从华为云拿到deviceId
        Device device = BeanUtil.toBean(dto, Device.class);
        //将缺少的三个字段填充进去
        device.setIotId(deviceId);
        device.setSecret(s);
        device.setHaveEntranceGuard(0);
        save(device);
    }

    /**
     * 查询设备的详细信息
     * @param iotId
     * @return
     */
    @Override
    public DeviceDetailVo queryDeviceDetail(String iotId) {
        //1.先查数据库
        Device device = lambdaQuery().eq(Device::getIotId, iotId).one();
        DeviceDetailVo vo = BeanUtil.toBean(device, DeviceDetailVo.class);
        //2.再查华为云
        ShowDeviceRequest request=new ShowDeviceRequest();
        request.setDeviceId(iotId);
        ShowDeviceResponse response = null;
        try {
            response = client.showDevice(request);
            if(response==null){
                throw new RuntimeException("调用华为云返回值为null");
            }
        } catch (Exception e) {
            throw new RuntimeException("调用华为云接口失败");
        }
        vo.setDeviceStatus(response.getStatus());
        String utcTimeStr = response.getActiveTime();
        // 步骤1：解析为 Instant（UTC 时间点）
        Instant instant = Instant.parse(utcTimeStr);

        // 步骤2：指定目标时区为 "Asia/Shanghai"（北京时间，东八区）
        ZoneId beijingZone = ZoneId.of("Asia/Shanghai");

        // 步骤3：将 Instant 转换为北京时间的 ZonedDateTime
        ZonedDateTime beijingZonedDateTime = instant.atZone(beijingZone);

        // 步骤4：提取 LocalDateTime（仅日期和时间，不带时区信息）
        LocalDateTime beijingLocalDateTime = beijingZonedDateTime.toLocalDateTime();
        vo.setActiveTime(beijingLocalDateTime);
        //3.合并数据返回给前端
        return vo;
    }

    /**
     * 获取设备的影子数据(最新的设备参数数据)
     * @param iotId
     * @return
     */
    @Override
    public AjaxResult queryServiceProperties(String iotId) {
        //1.获取华为云返回结果
        ShowDeviceShadowRequest request=new ShowDeviceShadowRequest();
        request.setDeviceId(iotId);
        ShowDeviceShadowResponse response = client.showDeviceShadow(request);
        //2.对结果进行解析
        DeviceShadowProperties reported = response.getShadow().get(0).getReported();
        String eventTime = reported.getEventTime();
        LocalDateTime activeTime= LocalDateTimeUtil.parse(eventTime, "yyyyMMdd'T'HHmmss'Z'");
        //日期时区转换
        LocalDateTime beijingLocalDateTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
                .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                .toLocalDateTime();
        JSONObject obj = JSONUtil.parseObj(reported.getProperties());//obj本质上是一个Map对象
        List<Map<String,Object>> mapList =new ArrayList<>();
        obj.forEach((k,v)->{
            Map<String,Object> map=new HashMap<>();
            map.put("functionId",k);
            map.put("eventTime",beijingLocalDateTime);
            map.put("value",v);
            mapList.add(map);
        });
        return AjaxResult.success(mapList);
    }

    /**
     * 修改设备
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatedevice(DeviceDto dto) {
        //先查询数据库有没有条数据
        Device dbDevice = getById(dto.getId());
        if(ObjectUtil.isEmpty(dbDevice)){
            throw new RuntimeException("设备不存在");
        }
        //1.更新数据库
        Device device = null;
        try {
            device = BeanUtil.toBean(dto, Device.class);
            updateById(device);
        } catch (Exception e) {
            throw new RuntimeException("该老人/位置已经绑定过该产品,请重新选择");
        }
        //2.更新华为云
        UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.setDeviceId(dto.getIotId());
        UpdateDevice body = new UpdateDevice();
        body.setDeviceName(device.getDeviceName());
        request.withBody(body);
        client.updateDevice(request);
    }

    /**
     * 删除设备信息
     */
    @Override
    public void deletedevice(String iotId) {
        //1.从数据库中删除
        remove(new LambdaQueryWrapper<Device>().eq(Device::getIotId,iotId));
        //2.从华为云删除
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.setDeviceId(iotId);
        client.deleteDevice(request);
    }

    @Override
    public AjaxResult queryProduct(String productId) {
        ShowProductRequest request=new ShowProductRequest();
        request.setProductId(productId);
        ShowProductResponse response = client.showProduct(request);
        List<ServiceCapability> list = response.getServiceCapabilities();
        return AjaxResult.success(list);
    }

}
